#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>

#include "pbd_linux.h"
#include "pbd_error.h"

#define MAX_IFR_NUM 10

static int pbd_is_loopdev(char *dev)
{
	int fd, ret;
	struct ifreq ifr;

	memset((char *)&ifr, 0, sizeof(struct ifreq));
	strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (!fd) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Create Socket Fail\n");
		return 1;
	}

	ret = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
	if (ret < 0) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Get %s Mac Address Fail\n", dev);
		goto out_close;
	}

	if (ifr.ifr_flags & IFF_LOOPBACK)
		goto out_close;

	close(fd);
	return 0;
	
out_close:
	close(fd);
	return 1;
}

static int pbd_link_state(char *dev)
{
	int fd, ret;
	struct ifreq ifr;

	memset((char *)&ifr, 0, sizeof(struct ifreq));
	strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name) - 1);
	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (!fd) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Create Socket Fail\n");
		return 0;
	}

	ret = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
	if (ret < 0) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Get %s Mac Address Fail\n", dev);
		goto out_close;
	}

	if(ifr.ifr_flags & IFF_UP == 0)
		goto out_close;

	close(fd);
	return 1;
	
out_close:
	close(fd);
	return 0;
}

char *pbd_get_device()
{
	int fd, ret;
	struct ifconf ifc;
	struct ifreq ifr[MAX_IFR_NUM], *ifrp, *ifrend;

	fd = socket(AF_INET, SOCK_DGRAM, 0);
	if (!fd) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Create Socket Fail\n");
		return NULL;
	}

	ifc.ifc_len = sizeof(struct ifreq) * MAX_IFR_NUM;
	ifc.ifc_req = ifr;
	ret = ioctl(fd, SIOCGIFCONF, &ifc);
	if (ret < 0) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Get Net Config File Fail\n");
		goto out_close;
	}

	ifrend = ifr + ifc.ifc_len / sizeof(struct ifreq);
	for (ifrp = ifr; ifrp < ifrend; ifrp++) {
		if (!strncmp(ifrp->ifr_name, "dummy", 5))
			continue;
		if (pbd_is_loopdev(ifrp->ifr_name))
			continue;
		if (!pbd_link_state(ifrp->ifr_name))
			continue;

		// debug
		pbd_print(PBD_LOG_INFO, PBD_FUN, "Select %s Device\n", ifrp->ifr_name);
		break;
	}

	if(!ifrp)
		goto out_close;

	close(fd);
	return strdup(ifrp->ifr_name);

out_close:
	close(fd);
	return NULL;
}

uint8 *pbd_get_hwaddr(char *device)
{
	int fd, ret;
	// non-re-entrant!
	static uint8 srcmac[6];
	struct ifreq ifr;

	if (!device) 
		return NULL;

	fd = socket(AF_INET, SOCK_STREAM, 0);
	if (!fd) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Create Socket Fail\n");
		return NULL;
	}

	memset((char *)&ifr, 0, sizeof(struct ifreq));
	strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name) - 1);
	ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';

	// get mac
	ret = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
	if (ret < 0) {
		pbd_print(PBD_LOG_WARNING, PBD_FUN, "Get %s Mac Address Fail\n", device);
		goto out_close;
	}
	close(fd);

	memcpy(srcmac, &ifr.ifr_hwaddr.sa_data, 6);

	// debug
	pbd_print(PBD_LOG_INFO, PBD_FUN, "Get Mac: %02x:%02x:%02x:%02x:%02x:%02x\n", 
		srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5]);
	
	return srcmac;

out_close:
	close(fd);
	return NULL;
}

